package com.pl.grainmall.search.thread;

import org.checkerframework.checker.units.qual.A;

import java.util.concurrent.*;

public class ThreadTest {
    //当前线程池只有一两个,每个异步任务,都提交给线程池去执行
    public static ExecutorService executor = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main......start........");
//        CompletableFuture.runAsync(()->{
//            System.out.println("当前线程"+Thread.currentThread().getId());
//            int i=10/2;
//            System.out.println("运行结果:"+i);
//
//        },executor);
        /**
         * 方法完成后的感知
         */
//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("运行结果:" + i);
//            return i;
//        }, executor).whenComplete((res,exception)->{
//            //虽然可以得到异常信息,但是没法修改返回数据
//            System.out.println("异步任务成功完成了......结果是: "+res+"...异常是:"+exception);
//        }).exceptionally(throwable -> {
//            //可以感知异常,同时返回默认值
//            return 10;
//        });

        //方法执行完成之后的处理
//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("运行结果:" + i);
//            return i;
//        }, executor).handle((res,thr)->{
//            if (res!=null){
//                return res*2;
//            }
//            if (thr!=null){
//                return 0;
//            }
//            return 0;
//        });
        /**
         * 线程串行化
         * 1) thenRun: 不能获取到上一步的执行结果
         *      thenRunAsync((res)->{
         *             System.out.println("任务2启动了..."+res);
         *         },executor);
         * 2) thenAcceptAsync; 可以接收上一步结果,但是没有返回值
         *      thenAcceptAsync((res)->{
         *             System.out.println("任务2启动了..."+res);
         *         },executor);
         * 3) thenApplyAsync : 可以接收上一步结果,而且有返回值
         *      thenApplyAsync((res)->{
         *             System.out.println("任务2启动了..."+res);
         *             return "hello "+res;
         *         },executor);
         *
         */
//        CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("运行结果:" + i);
//            return i;
//        }, executor).thenApplyAsync((res)->{
//            System.out.println("任务2启动了..."+res);
//            return "hello "+res;
//        },executor);

        /**
         * 两个都完成
         */

//        CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
//            System.out.println("任务1线程" + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("任务1结束:" + i);
//            return i;
//        }, executor);
//
//        CompletableFuture<Object>  future02= CompletableFuture.supplyAsync(() -> {
//            System.out.println("任务2线程" + Thread.currentThread().getId());
//
//            System.out.println("任务2结束:");
//            return "Hello";
//        }, executor);

//        future01.runAfterBothAsync(future02,()->{
//            System.out.println("任务3线程开始" + Thread.currentThread().getId());
//        },executor);
//        future01.thenAcceptBothAsync(future02,(f1,f2)->{
//            System.out.println("任务3开始....之前的结果: "+f1+"----->"+f2);
//        },executor);

//        CompletableFuture<String> future = future01.thenCombineAsync(future02, (f1, f2) -> {
//            return f1 + " : " + f2 + "  -> Haha";
//        }, executor);
        /**
         * 两个任务,只要有一个完成,我们就执行任务3
         * runAfterEitherAsync:不感知结果,自己没有返回值
         * acceptEitherAsync: 感知结果,自己没有返回值
         * applyToEitherAsync: 感知结果,有返回值
         */
//        CompletableFuture<Void> future = future01.runAfterEitherAsync(future02, () -> {
//            System.out.println("任务3开始....之前的结果: ");
//        }, executor);

//        CompletableFuture<Void> future = future01.acceptEitherAsync(future02, (res) -> {
//            System.out.println("任务3开始....之前的结果: ");
//        }, executor);

//        CompletableFuture<String> future = future01.applyToEitherAsync(future02, (res) -> {
//            System.out.println("任务3开始....之前的结果: ");
//            return res.toString() + "->哈哈";
//        }, executor);

        CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的图片信息");
            return "hello.jpg";
        },executor);
        CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的图片属性");
            return "黑色+ 256G";
        },executor);
        CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品的介绍");
            return "华为";
        },executor);
        CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
        allOf.get();//等待所有结果完成

        System.out.println("main......end........"+futureImg.get()+"=>"+futureAttr.get()+"=>"+futureDesc.get());
        System.out.println("main......end........"+allOf.get());
    }


    public void thread(String[] args) {
        /**
         * 1) 继承Thread
         * 2) 实现Runnable接口
         * 3) 实现Callable接口 + FutureTask (可以拿到会结果,可以处理异常)
         * 4) 线程池
         *        直接给线程池提交任务
         *        1) 创建  Executors
         *        2)  new ThreadPoolExecutor()
         *    Future:可以获取到异步结果
         *
         * 以后在业务代码中,上三种启动线程的方式都不用;【而是将所有的多线程异步任务都交给线程池执行】
         *
         * 区别:
         *      1,2不能获取到返回值;3可以获取返回值
         *      1,2,3都不能控制资源
         *      4的方式可以控制资源,性能稳定
         *
         */

        /**
         *七大参数
         * corePoolSize: 核心线程数[一直存在除非(allowCoreThreadTimeOut) ];线程池,创建好以后就准备的线程数量,就等待来接受异步任务去执行
         *    5个  Thread thread  =new Thread(); thread.start();
         * maximumPoolSize:最大线程数    控制资源
         * keepAliveTime: 存活时间 , 如果当前的线程数量大于核心数量
         *                 释放空闲的线程(maximumPoolSize-corePoolSize);只要线程的空闲时间大于keepAliveTime;
         * unit: 时间单位
         * workQueue: 阻塞队列;如果任务有很多,就将目前多的任务放在队列里面;
         *             只要线程空闲,就会去队列里面取出新的任务继续执行
         * threadFactory: 线程的创建工厂
         *
         * RejectedExecutionHandler handler: 如果队列满了,按照指定的拒绝策略拒绝执行任务
         *
         *
         * 工作顺序:
         *  1) 线程池创建,准备好core数量的核心线程,准备接受任务
         *      1.1) core 满了，就将再进来的任务放入阻塞队列中。空闲的 core 就会自己去阻塞队列获取任务执行
         *      1.2) 阻塞队列满了，就直接开新线程执行，最大只能开到 max 指定的数量
         *      1.3) max满了就用 RejectedExecutionHandler 拒绝任务
         *      1.4) max都执行完成,有很多空闲;在指定的时间keepAliveTime以后,会释放max-core这些线程
         *              new LinkedBlockingDeque<>() 默认是Integer的最大值;会造成内存不够
         *
         * 面试:
         *  一个线程池 core 7； max 20 ，queue：50，100 并发进来怎么分配的；
         * 先有 7 个能直接得到执行，接下来 50 个进入队列排队，在多开 13 个继续执行。现在 70 个
         * 被安排上了。剩下 30 个默认拒绝策略。
         * 如果不想抛弃还要执行;CallerRunsPolicy;
         *
         *  2) 新的任务进来，用 core 准备好的空闲线程执行。
         *
         */
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
                200,
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(10000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

//        Executors.newCachedThreadPool() core是0,所有都可以回
//        Executors.newFixedThreadPool()  固定大小,core=max;都不可以回收
//        Executors.newScheduledThreadPool()  定时任务的线程池
//        Executors.newSingleThreadExecutor()  单线程的线程池,后台从队列里面获取任务,挨个执行

        System.out.println("main......end........");

    }

    public static class Thread01 extends Thread {
        @Override
        public void run() {
            System.out.println("当前线程" + Thread.currentThread().getId());
        }
    }

}
